package net.metashare.grah.logic

import net.metashare.grah.NodeHandler

class DynamicPredicateFactory {


  def NodeHandler defaultHandler = PogoGraphObjectFactory.instance.getDefaultNodeHandler()
    // default object handler does nothing - but other handlers may choose
    // to do things like unwrap nodes down to objects, or use meta-data
    // to traverse down the object chain.

  

  def unwrap(Object o)
  {
    if ( o instanceof Node)
    {
      Node n = o ;
      return n.handler.unwrap(n)
    }
    else
      return defaultHandler.unwrap( o)
  }


  def predicateClosureMap = [
          "true":
          { true},
          "false":
          { false},
          "isA":
          {it, Object[] params, Predicate[] preds ->
          //{it, Class clzz ->
            Class clzz = params[0];
            clzz.getClass().isAssignableFrom(unwrap(it).getClass())
          },
          "property":
          {it, Object[] params, Predicate[] preds ->
            //{it, Object name, Predicate pred ->
            pred=preds[0]
            pred.apply(unwrap(it).getProperty(name))
          },

          "substring":
          {it, Object[] params, Predicate[] preds ->
            String param = params[0]//{it, Object param ->
            unwrap(it).find(param)
          },

          "equals":
          {it, Object[] params, Predicate[] preds ->
            //{it, Object param ->

            unwrap(it).equals(unwrap(params(0)))
          },
          "notEquals":
          {it, Object[] params, Predicate[] preds ->
            //{it, Object param ->
            !(unwrap(it).equals(unwrap(param(0))))
          },
          "not":
          {it, Object[] params, Predicate[] preds ->
            //{it, Predicate pred ->
            !(pred.apply(unwrap(it)))
          },
          "either":
          {it, Object[] params, Predicate[] preds ->
            //{it, Predicate[] pred ->
            pred[0].apply(unwrap(it)) ^ pred[1].apply(unwrap(it))
          },
          "or":
          {it, Object[] params, Predicate[] preds ->
            //{it, Predicate[] preds ->
            preds[0].apply(unwrap(it)) || preds[1].apply(unwrap(it))
          },
          "and":
          {it, Object[] params, Predicate[] preds ->
            //{it, Predicate[] preds ->
            preds[0].apply(unwrap(it)) && preds[1].apply(unwrap(it))
          },
          "any":
          {it, Object[] params, Predicate[] preds ->
            //{it, Predicate[] preds ->
            preds.each() { Predicate pred -> if (pred.apply(unwrap(it))) return true }
          },
          "none":
          {it, Object[] params, Predicate[] preds ->
            //{it, Predicate[] preds ->
            preds.each() { Predicate pred -> if (pred.apply(unwrap(it))) return false }
          },
          "between":
          {it, Object[] params, Predicate[] preds ->
            //{it, Object[] params ->
            (unwrap(it) >= params(0) && unwrap(it) <= params(1))
          },
          "lessThan":
          {it, Object[] params, Predicate[] preds ->
            //{it, Object[] params ->
            (unwrap(it) < params(0))
          },
          "lessOrEqualThan":
          {it, Object[] params, Predicate[] preds ->
            //{it, Object[] params ->
            (unwrap(it) <= params(0))
          },
          "greaterThan":
          {it, Object[] params, Predicate[] preds ->
            //{it, Object[] params ->
            (unwrap(it) > params(0))
          },
          "greaterOrEqualThan":
          {it, Object[] params, Predicate[] preds ->
            //{it, Object[] params ->
            (unwrap(it) >= params(0))
          }

  ]

/*

  def predicateClosureMap = [
          "true": True.&apply,
          "false": False.&apply,
          "isA": IsA.&apply,
          "testProperty": TestProperty.&apply,
          "substring": Substring.&apply,

          "equals": Equals.&apply,
          "notEquals": NotEquals.&apply,
          "not": Not.&apply,
          "either": Either.&apply,
          "or": Or.&apply,
          "and": And.&apply,
          "any": Any.&apply,
          "none": None.&apply,
          "between": Between.&apply,
          "lessThan": LessThan.&apply,
           "lessOrEqualThan": LessOrEqualThan.&apply,
          "greaterThan": greaterThan.&apply,
          "greaterOrEqualThan": GreaterOrEqualThan.&apply,

  ]
*/

  public Predicate getPredicate(String name, Object... args) {
    return predicateClosureMap.get(name)
  }

  public Predicate getPredicate(String name, List<Predicate> subPredicates) {
    def DynamicPredicate pred = new DynamicPredicate(predicateClosureMap.get(name))
    pred.subPredicates = subPredicates
  }


}
